package com.ug_project.dict.engine

import com.ug_project.dict.engine.entity.DictItem
import com.ug_project.dict.engine.indextable.DataBlock
import com.ug_project.dict.engine.indextable.PointerBlock
import com.ug_project.dict.engine.wordtable.printWords
import org.junit.Test
import java.nio.channels.FileChannel
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardOpenOption
import kotlin.system.measureTimeMillis

data class Segment(val items: Array<DictItem>)

class DictEngineTest {
    fun provideDictEngine(autoClean: Boolean = true, action: (DictEngine) -> Unit) {
        val wordTableFile = Paths.get("temp_wordtable.wdt")
        val indexTableFile = Paths.get("temp_indextable.ipt")
        val dataTableFile = Paths.get("temp_datatable.ddt")

        if (autoClean) {
            Files.deleteIfExists(wordTableFile)
            Files.deleteIfExists(indexTableFile)
            Files.deleteIfExists(dataTableFile)
        }

        if (Files.notExists(wordTableFile)) Files.createFile(wordTableFile)
        if (Files.notExists(indexTableFile)) Files.createFile(indexTableFile)
        if (Files.notExists(dataTableFile)) Files.createFile(dataTableFile)

        val wordTableChannel = FileChannel.open(wordTableFile, StandardOpenOption.READ, StandardOpenOption.WRITE)
        val indexTableChannel = FileChannel.open(indexTableFile, StandardOpenOption.READ, StandardOpenOption.WRITE)
        val dataTableChannel = FileChannel.open(dataTableFile, StandardOpenOption.READ, StandardOpenOption.WRITE)

        val engine = DictEngine(wordTableChannel, indexTableChannel, dataTableChannel)
        action(engine)

        wordTableChannel.close()
        indexTableChannel.close()
        dataTableChannel.close()


    }

    @Test
    fun addNewWord() {
        provideDictEngine(true) { engine ->

            engine.addNewWord(DictItem("S", "S ھەرىپى"))
            engine.addNewWord(DictItem("Start", "باشلاش"))
            engine.addNewWord(DictItem("Star", "يۇلتۇز"))
            engine.addNewWord(DictItem("Open", "ئىچىش"))
            engine.addNewWord(DictItem("Hello", "ياخشىمۇسىز"))

            engine.addNewWord(DictItem("google", "گۇگىل تور بىتى"))
            engine.addNewWord(DictItem("hell", "دوۋزاخ"))

            engine.wordTable.printWords()
        }
    }

    @Test
    fun search() {
        provideDictEngine(false) { engine ->
            val pointer = engine.wordTable['a'.toInt()]!!.pointers[0]
            val pointerBlock = PointerBlock(engine.indexTable, pointer)
            var ms = measureTimeMillis {
                pointerBlock.forEachIndexed { index, it ->
                    if (index > 100) return@forEachIndexed
                    val block = DataBlock(engine.indexTable, it)
                    val item = engine.dataTable.read(block.dataIndex)
//                    println(item)
                }
            }

            ms = measureTimeMillis {
                pointerBlock.forEachIndexed { index, it ->
                    if (index > 500) return@forEachIndexed
                    val block = DataBlock(engine.indexTable, it)
                    val item = engine.dataTable.read(block.dataIndex)
//                    println(item)
                }
            }
            val pointers = pointerBlock.allPointers
            ms = measureTimeMillis {
                pointers.forEachIndexed { index, it ->
                    if (index > 50) return@forEachIndexed
                    val block = DataBlock(engine.indexTable, it)
                    val item = engine.dataTable.read(block.dataIndex)
//                    println(index)
                }
            }

            println(ms)
        }
    }

    @Test
    fun readWrite() {
        provideDictEngine { engineSource ->
            //            engineSource.addNewWord(DictItem("Start", "باشلاش"))
//            engineSource.addNewWord(DictItem("Open", "ئىچىش"))
//            engineSource.addNewWord(DictItem("Hello", "ياخشىمۇسىز"))

            provideDictEngine(false) { engineReaded ->
                engineReaded.wordTable.forEach { k, v ->
                    print("row: ${k.toChar()}   ")
                    v.forEachIndexed { index, i ->
                        print("[$index: $i], ")
                    }
                    println()
                }
            }
        }
    }
}

